------------------------------------------------------------------------------------ -- Схема: прячемся в кавере ------------------------------------------------------------------------------------ class "evaluator_need_cover" (property_evaluator) function evaluator_need_cover:__init(storage, name) super(nil, name) self.st = storage end function evaluator_need_cover:evaluate() return xr_logic.is_active(self.object, self.st) or false end ---------------------------------------------------------------------------------------------------------------------- class "action_cover" (action_base) function action_cover:__init (npc_name, action_name, storage) super(nil, action_name) self.st = storage end function action_cover:initialize() action_base.initialize(self) end function action_cover:activate_scheme() self.st.signals = {} --' Высчитываем кавер. local base_point = self.st.path_center and patrol if (self.st.path_center) then local path = patrol(self.st.path_center) if (path) then base_point = path:level_vertex_id(0) end else local smart = SIMBOARD:get_smart_by_name(self.st.smart) if (smart) then base_point = smart.m_level_vertex_id end end if not (base_point) then base_point = self.object:level_vertex_id() end local direction_vector = vector():set(math.random(-100,100), 0, math.random(-100,100)) local base_vertex_id = level.vertex_in_direction(base_point, direction_vector, math.random(self.st.radius_min,self.st.radius_max)) local self_random_position = level.vertex_position(base_vertex_id) --' Получаем врага, относительно которого надо искать кавер self.enemy_random_position = self_random_position --' дефолтовая позиция local cover = nil local tcover = nil local cover_dist = 2 while cover == nil and cover_dist <= 4 do cover = self.object:best_cover(self_random_position, self.enemy_random_position, cover_dist, 1, 150) cover_dist = cover_dist + 1 end if cover == nil then --printf("cover is [nil]") self.cover_vertex_id = base_vertex_id self.cover_position = self_random_position --printf("cover doesn't exists -- cover_vertex [%s] cover_position [%s]", tostring(self.cover_vertex_id), vec_to_str(self.cover_position)) else if tcover ~= nil then self.cover_vertex_id = tcover.cover_vertex_id self.cover_position = tcover.cover_position else self.cover_vertex_id = cover:level_vertex_id() self.cover_position = cover:position() end --printf("cover exists -- cover_vertex [%s] cover_position [%s]", tostring(self.cover_vertex_id), vec_to_str(self.cover_position)) end if not self.object:accessible(self.cover_position) then local ttp = VEC_ZERO self.cover_vertex_id = self.object:accessible_nearest(self.cover_position, ttp) self.cover_position = level.vertex_position(self.cover_vertex_id) --printf("cover exists but not accesible -- cover_vertex [%s] cover_position [%s]", tostring(self.cover_vertex_id), vec_to_str(self.cover_position)) end local desired_direction = vec_sub(self.cover_position,self.enemy_random_position) --printf("desired_direction = %s", vec_to_str(desired_direction)) if desired_direction ~= nil and not utils_data.vector_cmp(desired_direction, VEC_ZERO) then desired_direction:normalize() self.object:set_desired_direction(desired_direction) end self.object:set_path_type(game_object.level_path) self.object:set_dest_level_vertex_id(self.cover_vertex_id) --printf("cover position is %s enemy position is %s", vec_to_str(self.cover_position), vec_to_str(self.enemy_random_position)) state_mgr.set_state(self.object, "assault") --printf("[%s]Setting cover %s", self.object:name(), self.cover_vertex_id) end function action_cover:execute() --printf("[%s] dist %s to %s", self.object:name(), self.cover_position:distance_to_sqr(self.object:position()), vec_to_str(self.cover_position)) --' Проверяем пришли ли в точку. if not (self.cover_position) then return end if self.cover_position:distance_to_sqr(self.object:position()) <= 0.4 then local anm = xr_logic.pick_section_from_condlist(db.actor, self.object, self.st.anm) state_mgr.set_state(self.object, anm) else self.object:set_dest_level_vertex_id(self.cover_vertex_id) state_mgr.set_state(self.object, "assault") end if self.st.sound_idle ~= nil then xr_sound.set_sound_play(self.object:id(), self.st.sound_idle) end action_base.execute(self) end function action_cover:finalize() action_base.finalize(self) end --' Возвращает достиг ли персонаж точки начала работы схемы function action_cover:position_riched() return self.cover_position:distance_to_sqr(self.object:position()) <= 0.4 end ---------------------------------------------------------------------------------------------------------------------- -- binder ---------------------------------------------------------------------------------------------------------------------- function add_to_binder(npc, ini, scheme, section, storage) if not npc then return end local operators = {} local properties = {} local manager = npc:motivation_action_manager() if not manager then return end properties["event"] = xr_evaluators_id.reaction properties["need_cover"] = xr_evaluators_id.stohe_cover_base + 1 properties["state_mgr_logic_active"] = xr_evaluators_id.state_mgr + 4 operators["action_cover"] = xr_actions_id.stohe_cover_base + 1 -- evaluators local evaluator = this.evaluator_need_cover(storage, "need_cover") local new_action = this.action_cover(npc, "action_cover", storage) if not evaluator or not new_action then return end manager:add_evaluator(properties["need_cover"], evaluator) new_action:add_precondition(world_property(stalker_ids.property_alive,true)) new_action:add_precondition(world_property(stalker_ids.property_danger,false)) new_action:add_precondition(world_property(stalker_ids.property_enemy,false)) new_action:add_precondition(world_property(xr_evaluators_id.sidor_wounded_base + 0,false)) new_action:add_precondition(world_property(properties["need_cover"],true)) new_action:add_effect(world_property(properties["need_cover"],false)) new_action:add_effect (world_property(properties["state_mgr_logic_active"], false)) manager:add_action(operators["action_cover"], new_action) -- Зарегистрировать все actions, в которых должен быть вызван метод reset_scheme при изменении настроек схемы: xr_logic.subscribe_action_for_events(npc, storage, new_action) --printf("ACTION_ALIFE_ID(xr_cover.add_to_binder): " .. tostring(xr_actions_id.alife)) new_action = manager:action(xr_actions_id.alife) if new_action then new_action:add_precondition(world_property(properties["need_cover"], false)) end end -- Включение схемы function set_scheme(npc, ini, scheme, section, gulag_name) local st = xr_logic.assign_storage_and_bind(npc, ini, scheme, section) st.logic = xr_logic.cfg_get_switch_conditions(ini, section, npc) st.smart = ini:r_string_ex(section,"smart") st.path_center = ini:r_string_ex(section,"path_center") st.anm = xr_logic.parse_condlist(npc, "anim", "anim", ini:r_string_ex(section,"anim") or "hide") st.sound_idle= ini:r_string_ex(section,"sound_idle") if (st.smart== nil and st.path_center == nil) then printf("There is no path_center or smart in xr_cover.") end st.use_attack_direction = ini:r_bool_ex(section,"use_attack_direction",true) st.radius_min = ini:r_float_ex(section,"radius_min") or 3 st.radius_max = ini:r_float_ex(section,"radius_max") or 7 end